﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace EasyClass {
	public class DataClass {
		private Dictionary<string, Task> tasks;  //taskName
		private Dictionary<string, Topic> topics;  //topicName
		private Dictionary<Task, AllAnswer> submissions;  //submitted answers
		//private Dictionary<Topic, AllTeam> teams;  //submitted answers
		private Dictionary<string, Account> students;  //registered students
		private HashSet<string> limit;  //leagal student list

		private Controller controller;


		public DataClass(Controller c) {
			controller = c;
			controller.SetDataClass(this);
			tasks = new Dictionary<string, Task>();
			students = new Dictionary<string, Account>();
			submissions = new Dictionary<Task, AllAnswer>();
			topics = new Dictionary<string, Topic>();
			limit = new HashSet<string>();
		}

		public void AddTask(Task task) {
			tasks[task.taskName] = task;
			submissions[task] = new AllAnswer(task);
			//debug
			//submissions[task].answers["bantu"] = new string[2]{"AC", "C"};
			//submissions[task].answers["lvxiao"] = new string[2] { "CD", "I" };
			//submissions[task].answers["lvxiao2"] = new string[2] { "AC", "I" };
			//MyConsole.WriteLine("Add task" + " " + submissions.Count);
		}

		public void DeleteTask(string taskName) {
			submissions.Remove(GetTask(taskName));
			tasks.Remove(taskName);
		}

		public Task GetTask(string taskName) {
			if (!tasks.ContainsKey(taskName)) return null;
			return tasks[taskName];
		}

		public string[] GetAllTasksName() {
			return tasks.Keys.ToArray();
		}

		public void AddProblem(string taskName, Problem problem) {
			tasks[taskName].problems.Add(problem);
		}


		public void AddTopic(Topic topic) {
			topics[topic.topicName] = topic;
		}

		public void DeleteTopic(string topicName) {
			topics.Remove(topicName);
		}

		public Topic GetTopic(string topicName) {
			if (!topics.ContainsKey(topicName)) return null;
			return topics[topicName];
		}

		public string[] GetAllTopicsName() {
			return topics.Keys.ToArray();
		}

		public bool AddTeam(Team team, ref string reason) {
			List<Team> teams = topics[team.topic.topicName].teams;
			foreach (Team t in teams) {
				if (t.teamName == team.teamName) {
					reason = "Team name exists";
					return false;
				}
				if (t.ContainMember(team.captainID)) {
					reason = "Already joined one team in this topic";
					return false;
				}
			}
			team.topic.teams.Add(team);
			return true;
		}

		public bool TryExitTeam(Dictionary<string, string> dict, ref string reason) {
			List<Team> teams = topics[dict["TopicName"]].teams;
			foreach (Team t in teams) {
				if (t.status == 1) {
					reason = "Team is locked";
					return false;
				}

				if (t.teamName == dict["TeamName"]) {
					string studentID = dict["StudentID"];
					if (studentID == t.captainID) {
						teams.Remove(t);
					} else {
						t.members.Remove(studentID);
					}
					return true;
				}
			}
			reason = "StudentID not found";
			return false;
		}

		public bool TryJoinTeam(Dictionary<string, string> dict, ref string reason) {
			List<Team> teams = topics[dict["TopicName"]].teams;
			string teamName = dict["TeamName"];
			string studentID = dict["StudentID"];
			Team team = null;
			foreach (Team t in teams) {
				if (t.members.Contains(studentID)) {
					reason = "Student is already in one team of this topic";
					return false;
				}

				if (t.teamName == dict["TeamName"]) {
					if (t.status == 1) {
						reason = "Team is locked";
						return false;
					}
					team = t;
				}
			}
			if (team == null) {
				reason = "Team not found";
				return false;
			}
			if (team.password != dict["Password"]) {
				reason = "Wrong password";
				return false;
			}
			team.members.Add(studentID);
			return true;
		}

		public bool TryLockTeam(Dictionary<string, string> dict, ref string reason) {
			Topic topic = topics[dict["TopicName"]];
			foreach (Team t in topic.teams) {
				if (t.teamName == dict["TeamName"]) {
					if (t.members.Count + 1 <= topic.lower) {
						reason = "# of people is lower than lower bound";
						return false;
					}
					t.status = 1;
					return true;
				}
			}
			reason = "Team not found";
			return false;
		}

		public bool TryUnlockTeam(Dictionary<string, string> dict, ref string reason) {
			List<Team> teams = topics[dict["TopicName"]].teams;
			foreach (Team t in teams) {
				if (t.teamName == dict["TeamName"]) {
					t.status = 0;
					return true;
				}
			}
			reason = "Team not found";
			return false;
		}

		public bool TryKickMember(Dictionary<string, string> dict, ref string reason) {
			List<Team> teams = topics[dict["TopicName"]].teams;
			foreach (Team t in teams) {
				if (t.status == 1) {
					reason = "Team is locked";
					return false;
				}

				if (t.teamName == dict["TeamName"]) {
					string studentID = dict["StudentID"];
					if (t.members.Contains(studentID)) {
						t.members.Remove(studentID);
						return true;
					}
					reason = "Student isn't in the team";
					return false;
				}
			}
			reason = "Team not found";
			return false;
		}

		public bool TryRegister(Dictionary<string, string> dict, ref string reason) {
			if (!dict.ContainsKey("Email")) dict["Email"] = "";
			string studentID = dict["StudentID"];
			if (students.ContainsKey(studentID)) {
				reason = "StudentID has been registered";
				return false;
			} else {
				if (limit.Count > 0 && !limit.Contains(studentID)) {
					reason = "StudentID isn't in the list";
					return false;
				}
				students[studentID] = new Account(studentID, dict["Password"], dict["Email"]);
				return true;
			}
		}

		public bool TryLogin(Dictionary<string, string> dict, ref string reason) {
			string studentID = dict["StudentID"];
			if (students.ContainsKey(studentID) && students[studentID].password == dict["Password"]) {
				students[studentID].status = 1;
				return true;
			} else {
				reason = "StudentID not registered or wrong password";
				return false;
			}
		}

		public bool TryLogoff(Dictionary<string, string> dict, ref string reason) {
			string studentID = dict["StudentID"];
			if (students.ContainsKey(studentID) && students[studentID].password == dict["Password"]) {
				students[studentID].status = 0;
				return true;
			} else {
				reason = "StudentID not registered or wrong password";
				return false;
			}
		}

		public bool  TrySubmitAnswer(Dictionary<string, string> dict, ref string reason) {
			string[] newAnswer = dict["Answer"].Split(' ');
			Task task = GetTask(dict["TaskName"]);
			if (task == null) {
				reason = "Task does not exist";
				return false;
			}
			return submissions[task].TrySubmitAnswer(dict["StudentID"], newAnswer, ref reason);
		}

		public void ClearLimit() {
			limit.Clear();
		}

		public HashSet<string> GetLimit() {
			return limit;
		}

		public Dictionary<string, Account> GetStudents() {
			return students;
		}

		public void SetLimit(HashSet<string> l) {
			limit = l;
		}

		public void CreateTxtLog(string taskName, string path) {
			submissions[GetTask(taskName)].CreateTxtLog(path);
		}

		/*public void JudgeAnswers(string taskName, ref int right, ref int wrong) {
			Task task = GetTask(taskName);
			for (int i = 0; i < task.problems.Count; ++i) {
				
			}
		}*/

		public bool ContainSubmission(string taskName) {
			return submissions[GetTask(taskName)].answers.Count > 0;
		}

		public void CleanSubmission(string taskName) {
			submissions[GetTask(taskName)].answers.Clear();
		}

		public bool ContainTeam(string topicName) {
			return topics[topicName].teams.Count > 0;
		}

		public void CleanTeam(string topicName) {
			topics[topicName].teams.Clear();
		}

		public AllAnswer GetAllAnswer(string taskName) {
			return submissions[GetTask(taskName)];
		}

		public void ExportTopicsAndTeams(string path) {
			StreamWriter sr = File.CreateText(path);
			foreach (Topic topic in topics.Values)
				sr.WriteLine(topic.Export());
			sr.Close();
		}
	}
}
